﻿// <copyright file="RenderEntityPool.cs" company="Axelerate Solutions S.A.">
// Copyright (c) Axelerate Solutions S.A.  All rights reserved.
// </copyright>
namespace Axelerate.Silverlight3D.Media.Media3D
{
    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Collections.Generic;
    using Axelerate.Silverlight3D.Controls;
    
    /// <summary>
    /// File name: RenderEntityPool.cs
    /// Company: Axelerate Solutions S.A.
    /// Created By: Daniel Rojas
    /// Created Date: 11/06/2008 17:16:30 h.
    /// Description: Keep a Queue of render entities to recycle the instances between renders and imprube the performance 
    ///   <Modifications>
    ///   </Modifications>
    /// </summary>
    internal sealed class RenderEntityPool
    {
        /// <summary>
        /// Viewport object owner of the pool.
        /// </summary>
        private Viewport3D owner;
        
        /// <summary>
        /// Queue of render entities.
        /// </summary>
        private Queue<RenderEntity> renderEntities;

        /// <summary>
        /// Number of items to add when a renderentity is requerire and don't have more on the queue
        /// </summary>
        private int blockSize = 100;

        /// <summary>
        /// Create a new instance of the RenderEntityPool
        /// </summary>
        /// <param name="owner">Viewport3D owner of this pool</param>
        public RenderEntityPool(Viewport3D owner)
        {
            this.owner = owner;
            this.renderEntities = new Queue<RenderEntity>(blockSize);
            CreateRenderEntityBlock();
        }

        /// <summary>
        /// Get a render entity from the pool and intialize it. if is necesary create a new block of render entities.
        /// </summary>
        /// <param name="mesh">Mesh ouner of the render entity if apply. (can be null)</param>
        /// <param name="v0Index">vertex 0 of the triangle if applay. (can be -1)</param>
        /// <param name="v1Index">vertex 1 of the triangle if applay. (can be -1)</param>
        /// <param name="v2Index">vertex 2 of the triangle if applay. (can be -1)</param>
        /// <param name="frontMaterial">Associated material for front face (if apply, can be null)</param>
        /// <param name="backMaterial">Associated material for back face (if apply, can be null)</param>
        /// <returns></returns>
        public RenderEntity GetRenderEntity(MeshGeometry3D mesh,
                                    int v0Index,
                                    int v1Index,
                                    int v2Index,
                                    Material frontMaterial,
                                    Material backMaterial)
        {
            if (renderEntities.Count == 0)
            {
                CreateRenderEntityBlock();
            }

            RenderEntity t = renderEntities.Dequeue();
            t.Initialize(mesh, v0Index, v1Index, v2Index, frontMaterial, backMaterial);
            return t;
        }

        /// <summary>
        /// Renturn entities to the pool to be recycled.
        /// </summary>
        /// <param name="t">list of render entities by model to be refounded.</param>
        public void ReturnToPool(Dictionary<Model3D, List<RenderEntity>> t)
        {
            //TODO: Think about removing this check for performance
            foreach (List<RenderEntity> modelRenderEntitys in t.Values)
            {
                foreach (RenderEntity RenderEntity in modelRenderEntitys)
                {
                    RenderEntity.Clear();
                    renderEntities.Enqueue(RenderEntity);
                }
            }
        }

        /// <summary>
        /// Return a single render entity to the pool.
        /// </summary>
        /// <param name="t">RenderEntity to be returned to the pool</param>
        public void ReturnToPool(RenderEntity t)
        {
            t.Clear();
            renderEntities.Enqueue(t);
        }

        /// <summary>
        /// Return a list of render entities to the pool.
        /// </summary>
        /// <param name="RenderEntitysToReturn">List of render entities to be recycled.</param>
        public void ReturnToPool(List<RenderEntity> RenderEntitysToReturn)
        {
            foreach (RenderEntity t in RenderEntitysToReturn)
            {
                t.Clear();
                renderEntities.Enqueue(t);
            }
        }

        /// <summary>
        /// Create a new block of render entities on the pool.
        /// </summary>
        private void CreateRenderEntityBlock()
        {
            for (int i = 0; i < blockSize; ++i)
            {
                RenderEntity t = new RenderEntity(this);
                renderEntities.Enqueue(t);
            }
        }
    }
}
